//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2011 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _BUOLA_CONTAINER_CBITSET_H_
#define _BUOLA_CONTAINER_CBITSET_H_

#include <buola/buola.h>
#include <bitset>

namespace buola {

///\addtogroup container
///@{

/////////////////////////////////////////////////////////////////////////////////////////////////

/// bit-based set

/// Set of objects of some integral type where the presence of each element is determined by
/// some bit being set. For this reason, it can only be used with 8 or 16-bit integral types,
/// or the memory requirements would be too large.
///
/// It basically wraps std::bitset with the same interface as \ref CRangeSet, so that it can
/// be used by \ref CCharSet.
///
/// \tparam tChar the integral type.
///
/////////////////////////////////////////////////////////////////////////////////////////////////
    
template<typename tChar>
class CBitSet
{
    ///unsigned version of \p tChar, to use as an index to the \c std::bitset
    typedef typename std::make_unsigned<tChar>::type tUnsigned;
    
public:
    static_assert(sizeof(tChar)<=2,"wrong size for bitrangerun");

    ///default constructor
    CBitSet()
    {}
    
    ///copy constructor
    CBitSet(const CBitSet &pRH)
        :   mSet(pRH.mSet)
    {}
    
    ///tests if a character \p pC is part of the set
    bool Test(tChar pC) const
    {
        return mSet.test((tUnsigned)pC);
    }
    
    ///adds the character \p pC to the set
    void Add(tChar pC)
    {
        mSet.set((tUnsigned)pC);
    }

    ///adds the range [\p pFirst,\p pLast] to the set
    void Add(tChar pFirst,tChar pLast)
    {
        if(pLast<pFirst) return;
        for(tUnsigned i=(tUnsigned)pFirst;i<=(tUnsigned)pLast;i++)
            mSet.set(i);
    }

    ///adds the set \p pSet to this set
    void Add(const CBitSet &pSet)
    {
        mSet|=pSet.mSet;
    }

    ///removes the range [\p pFirst,\p pLast] from the set
    void Remove(tChar pFirst,tChar pLast)
    {
        if(pLast<pFirst) return;
        for(tUnsigned i=(tUnsigned)pFirst;i<=(tUnsigned)pLast;i++)
            mSet.reset(i);
    }

    ///removes the character \p pC from the set
    void Remove(tChar pChar)
    {
        mSet.reset((tUnsigned)pChar);
    }

    ///removes the set \p pSet from this set
    void Remove(const CBitSet &pSet)
    {
        mSet&=~pSet.mSet;
    }

    ///inverts the set
    void Invert()
    {
        mSet.flip();
    }
    
    ///sets this set to be the intersection of itself with \p pSet
    void Intersect(const CBitSet &pSet)
    {
        mSet&=pSet.mSet;
    }

    ///toggles all elements present in \p pSet
    void Xor(const CBitSet &pSet)
    {
        mSet^=pSet.mSet;
    }

    ///removes all elements from the set
    void clear()
    {
        mSet.reset();
    }

private:
    std::bitset<1<<(8*sizeof(tChar))> mSet;
};

///@}

/*namespace buola*/ }

#endif
